package com.sanhuo.utils.basic;


import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author zzs
 * @version 1.0
 * @describe 反射工具类
 * @createTime 2018.1.5
 */
public class ReflectionUtil {
    /**
     * 判断是否为某一类型,field是反射中的变量
     * Class类中有 field 字段 method 方法 construction 构造函数
     *
     * @param field 判断的字段
     * @param clazz 是否为这个类型
     * @return boolean
     */
    public static Boolean isType(Field field, Class clazz) {
        return field.getType().equals(clazz);
    }

    public static Boolean isType(String typeName, Class clazz) {
        return typeName.equals(clazz.getTypeName());
    }

    public static Method getMethod(Class clazz, String methodName, Class argClass) {
        try {
            return clazz.getDeclaredMethod(methodName, argClass);
        } catch (NoSuchMethodException e) {
            try {
                return clazz.getSuperclass().getDeclaredMethod(methodName, argClass);
            } catch (NoSuchMethodException e1) {
                return null;
            }
        }

    }

    public static Method[] getMethods(Class clazz) {
        List<Method> methods = new ArrayList<>();
        while (clazz != Object.class) {
            methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
            clazz = clazz.getSuperclass();
        }
        return methods.toArray(new Method[0]);
    }

    /**
     * 获取类名
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> String getClassName(T t) {
        Class clazz = t.getClass();
        return clazz.getSimpleName();
    }

    /**
     * 获取类中的字段列表(包括继承的父类)
     *
     * @param t
     * @param <T>
     * @return
     */
    public static <T> Field[] getFieldList(T t) {
        Class clazz = t.getClass();
        Field[] fields = clazz.getDeclaredFields();
        List<Field> result = new ArrayList<>(Arrays.asList(fields));
        clazz = clazz.getSuperclass(); //得到父类,然后赋给自己
        if (clazz != null) {
            result.addAll(Arrays.asList(clazz.getDeclaredFields()));
        }

        //获取声明字段
        return result.toArray(new Field[0]);
    }

    /**
     * 通过字段名强制获取该字段的值
     *
     * @param t
     * @param fieldName
     * @param <T>
     * @return
     */
    public static <T> Object getFieldValueForce(T t, String fieldName) {
        Class clazz = t.getClass();
        Object value = null;
        try {
            Field field = clazz.getDeclaredField(fieldName);
            value = getFieldValue(t, field);

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        return value;
    }
//    public static Field getField(Class clazz,String fieldName){
//        try{
//            return clazz.getDeclaredField(fieldName);
//        } catch (NoSuchFieldException e) {
//            e.printStackTrace();
//        }
//    }

    /**
     * 获取实例t里面的field字段的值
     *
     * @param t     传进来的实例
     * @param field 获取该字段的值
     * @param <T>
     * @return
     */
    public static <T> Object getFieldValue(T t, Field field) {
        Object value = null;
        //private的时候是false不允许访问该字段,要设置为true才能访问
        field.setAccessible(true);
        try {
            value = field.get(t);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return value;
    }

    /**
     * 通过fieldName获取field然后给实例t中的field设置value
     *
     * @param t
     * @param fieldName
     * @param value
     * @param <T>
     */
    public static <T> void setFieldValueForce(T t, String fieldName, Object value) {
        Class clazz = t.getClass();
        try {
            Field field = clazz.getDeclaredField(fieldName);
            setFieldValue(t, field, value);

        } catch (NoSuchFieldException e) {
            try {
                clazz = t.getClass().getSuperclass();
                Field field = clazz.getDeclaredField(fieldName);
                setFieldValue(t, field, value);
            } catch (NoSuchFieldException e1) {
                e1.printStackTrace();
            }
//            e.printStackTrace();
        }


    }

    /**
     * 给实例t中的field字段设置value值
     *
     * @param t
     * @param field
     * @param value
     * @param <T>
     */
    public static <T> void setFieldValue(T t, Field field, Object value) {
        field.setAccessible(true);
        try {
            field.set(t, value);
        } catch (IllegalAccessException e) {
//            if(e.getMessage().contains(" Can not set java.lang.Integer")){
////                Object value = f.
//                try {
//                    String clazz = t.getClass().getDeclaredField(field.getName()).getType().getSimpleName();
//                    System.out.println( clazz);
//                } catch (NoSuchFieldException e1) {
//                    e1.printStackTrace();
//                }
//            }
            e.printStackTrace();
        }
    }

    /**
     * 判断t中是否有name这个字段
     *
     * @param t
     * @param name
     * @param <T>
     * @return
     */
    public static <T> Boolean isExistsFielt(T t, String name) {
        for (Field field : getFieldList(t)) {
            if (field.getName().equals(name)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取List里面的类型
     *
     * @param field
     * @return
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static Object getListCalssEntity(Field field) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        ParameterizedType listGenericType = (ParameterizedType) field.getGenericType();
        Type[] listActualTypeArguments = listGenericType.getActualTypeArguments();
        return Class.forName(listActualTypeArguments[0].getTypeName()).newInstance();
    }

    public static Object getListCalssEntity(Object arg) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        ParameterizedType listGenericType = (ParameterizedType) arg;
        Type[] listActualTypeArguments = listGenericType.getActualTypeArguments();
        return Class.forName(listActualTypeArguments[0].getTypeName()).newInstance();
    }

    public static Object getListType(Method method) {
        ParameterizedType listGenericType = (ParameterizedType) method.getGenericReturnType();
        Type[] listActualTypeArguments = listGenericType.getActualTypeArguments();
        return listActualTypeArguments[0].getTypeName();
    }

    public static Object getListCalssEntity(Method method) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        ParameterizedType listGenericType = (ParameterizedType) method.getGenericReturnType();
        Type[] listActualTypeArguments = listGenericType.getActualTypeArguments();
        if(listActualTypeArguments[0].getTypeName().equals("java.lang.Double")){
            return new Double(0);
        }
        if(listActualTypeArguments[0].getTypeName().equals("java.lang.Integer")){
            return new Integer(0);
        }
        return Class.forName(listActualTypeArguments[0].getTypeName()).newInstance();
    }

    /**
     * 根据名称获取对应的字段
     *
     * @param t
     * @param name
     * @param <T>
     * @return
     * @throws NoSuchFieldException
     */
    public static <T> Field getFieldByName(T t, String name) {
        if (isExistsFielt(t, name)) {
            try {
                return t.getClass().getDeclaredField(name);
            } catch (NoSuchFieldException e) {
                try {
                    return t.getClass().getSuperclass().getDeclaredField(name);
                } catch (NoSuchFieldException e1) {
                    e1.printStackTrace();
                }

            }

        }
        return null;
    }

    /**
     * 返回 t类上的注解的信息
     *
     * @param t
     * @param annotationClass
     * @param <T>
     * @return
     */
    public static <T> Annotation getAnnotation(T t, Class annotationClass) {
        Class clazz = t.getClass();
        return clazz.getAnnotation(annotationClass);
    }

    /**
     * 返回字段field上的注解信息
     *
     * @param field
     * @param annotationClass
     * @param <T>
     * @return
     */
    public static <T> Annotation getAnnotation(Field field, Class annotationClass) {

        return field.getAnnotation(annotationClass);
    }

    /**
     * 判断是否是基础类型及它的包装类型
     *
     * @param clazz
     * @return
     */
    public static boolean isPrimitive(Class clazz) {
        String classType = clazz.getName();
        return isPrimitive(classType);

    }

    public static boolean isPrimitive(Type type) {
        String classType = type.getTypeName();
        return isPrimitive(classType);

    }

    public static boolean isPrimitive(Object obj) {
        String classType = ((Object) obj).getClass().getTypeName();
        return isPrimitive(classType);

    }

    public static boolean isPrimitive(String classType) {
        return "java.lang.String".equals(classType) ||
                "java.lang.Double".equals(classType) ||
                "java.lang.Integer".equals(classType) ||
                "java.lang.Boolean".equals(classType) ||
                "java.lang.Float".equals(classType) ||
                "java.lang.Long".equals(classType) ||
                "java.lang.Character".equals(classType) ||
                "java.lang.Short".equals(classType) ||
                "java.lang.Byte".equals(classType);
    }


    public static boolean isPrimitive(Object[] args) {
        boolean result = false;
        for (Object arg : args) {
            String classType = ((Object) arg).getClass().getTypeName();
            result = result || isPrimitive(classType);
        }
        return result;
    }

    public static boolean isPage(Method method) {
        Type type = method.getReturnType();
        return isPage(type.getTypeName());
    }

    public static boolean isPage(String typeName) {
        return "com.sanhuo.triild.page.Page".equals(typeName);

    }

    /**
     * 判断是不是int类型
     *
     * @param arg
     * @return
     */
    public static boolean isInt(Object arg) {
        String classType = ((Object) arg).getClass().getTypeName();
        return "java.lang.Integer".equals(classType);
    }

    public static boolean isInt(Type type) {
        String classType = type.getTypeName();
        return "java.lang.Integer".equals(classType);
    }

    /**
     * 判断该实体类是否有该名称的字段
     *
     * @param entity
     * @param fieldName
     * @param <T>
     * @return
     */
    public static <T> boolean haveField(T entity, String fieldName) {
        try {
            Field field = entity.getClass().getDeclaredField(fieldName);
        } catch (NoSuchFieldException e) {
            try {
                Class clazz = entity.getClass().getSuperclass();
                Field field = clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e1) {
                return false;
            }

        }
        return true;
    }


    /**
     * 获取该属性的实体类
     *
     * @param arg
     * @return
     */
    public static Object getParamEntity(Object arg) {
        Object result = null;
        try {
            result = ((Object) arg).getClass().newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 获取该class的实例
     *
     * @param className
     * @return
     */
    public static Object getInstance(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        return Class.forName(className).newInstance();
    }


    public static Object getInstance(Class clazz) throws IllegalAccessException, InstantiationException {
        return clazz.newInstance();
    }


    public static Class getTClass(Object object) {
        Type type = object.getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] ptype = ((ParameterizedType) type).getActualTypeArguments();
            return (Class) ptype[0];
        }
        return null;
    }
}
